#dir Mateo
df_artist <- read.csv("data/df_artist_sin_duplicados.csv")
df_charts <- read.csv("data/df_charts_sin_duplicados.csv")
df_audio_features <- read.csv("data/audio_features_plano_sin_duplicados.csv")
nrow(df_charts)
nrow(df_audio_features)
features_categoricas <-c( 'explicit', 'key_name', 'mode_name',
"key_mode", "album_type")#,
#"artist_concat", "markets_concat")
features_continuas <- c('acousticness', 'danceability', 'duration_ms', 'energy',
'instrumentalness', 'liveness', 'loudness', 'speechiness',
'tempo', 'valence')
# features_categoricos <-c( explicit, disc_number,key_name, mode_name, key_mode, album_type)
# time_signature
summary(df_audio_features[,features_categoricas])
table(df_audio_features$album_type)
#observo que artistas y tipo de albunes son los que tienen muchos disc_number
unique(df_audio_features[df_audio_features$disc_number > 8,]$artist_name)
unique(df_audio_features[df_audio_features$disc_number > 10,]$album_type)
sort(table(df_audio_features[,"key_name"]), decreasing = T)
for(i in features_categoricos){
print(i)
barplot(sort(table(df_audio_features[,i]),decreasing = T), main = i, las=2)
# pie(table(df_features_categoricos[,i]))
}
Correlacion entre variables categóricas
tabla_key_album <- table(df_audio_features$key_name, df_audio_features$album_type)
cat("Tabla de contigencia entre key y album type\n")
tabla_key_album
chisq.test(tabla_key_mode)
Se observan valores altos del test chi cuadrado, por lo que se puede rechazar la H0 (variables categoricas independientes) y afirmar la dependencia de las variables
tabla_key_mode <- table(df_audio_features$explicit, df_audio_features$album_type)
cat("Tabla de contigencia entre key y album type\n")
tabla_key_mode
chisq.test(tabla_key_mode)
contar_market <- function(x){
q <- length(unlist(strsplit(x, split = ",")))
return (q)
}
df_audio_features$cant_markets <- sapply(df_audio_features[,"markets_concat"], contar_market)
summary(df_audio_features$cant_markets) #hay canciones en cero países. Están dadas de baja
x <- df_audio_features %>%
group_by(track_name, external_urls_spotify)
x$cant_markets <- sapply(x[,"markets_concat"], contar_market)
summary(x$cant_markets) #hay canciones en cero países. Están dadas de baja
Join Charts y Audio Features
Nueva key de artist para el JOIN
x <- df_audio_features %>%
group_by(track_name, external_urls_spotify) %>%
mutate(artist_new = paste(artist_name, collapse = ",|,")) %>%
ungroup() %>%
mutate(artist_key = sub(",|,.*", "", artist_new)) %>%
select(artist_name, artist_new, artist_key, everything(.)) %>%
distinct(artist_key, external_urls_spotify, .keep_all = T)
length(x[1,x$markets_concat])
join_audio_charts <- x %>%
select("artist_name","artist_new","artist_key",
"track_name", "external_urls_spotify",
features_continuas, features_categoricas) %>%
right_join( df_charts %>%
select( "Track_Name", "Artist",
"URL","Position", "Streams", "week_start", "week_end"),
by = c(
# "track_name" = "Track_Name",
"artist_key" ="Artist",
"external_urls_spotify" = "URL"))
###################
y <- join_audio_charts %>%
filter(grepl("d32M6", external_urls_spotify))# %>%
# distinct(Position, week_start)
glimpse(join_audio_charts)
nrow(df_audio_features)
nrow(x)
nrow(df_charts)
nrow(join_audio_charts)
sum(!complete.cases(df_audio_features))
sum(!complete.cases(join_audio_charts))
sum(complete.cases(join_audio_charts))
length(unique(join_audio_charts$artist_name))
# filter(grepl("d32M6", external_urls_spotify)) %>%
x
x %>% select(artist_key, artist_new,everything(.)) %>%
filter(grepl("|", artist_new))
join_audio_artist <- df_audio_features %>%
select("artist_name", "track_name", features_num, features_categoricos) %>%
right_join( df_charts %>%
select( "Track_Name", "Artist" ),
# "Position", "Streams", "week_start", "week_end"),
by = c("track_name" = "Track_Name", "artist_name" ="Artist" ))
join_audio_artist <- df_charts %>%
select( "Track_Name", "Artist", "URL", "Position", "Streams", "week_start", "week_end") %>%
# distinct() %>%
left_join( df_audio_features %>%
select("artist_name", "track_name", "external_urls_spotify", features_num, features_categoricos),
by = c( "URL"= "external_urls_spotify" ))
join_audio_artist
# glimpse(df_audio_features)
# glimpse(df_charts)
Analisis de NA’s de Audio Feature
sum(is.na(join_audio_artist))
sum(!complete.cases(join_audio_artist))
sum(is.na(df_audio_features))
sum(is.na(df_charts))
library(mice)
md.pattern(join_audio_artist, rotate.names = T)
library(VIM)
# Proporción de cada combinación
faltantes = summary(aggr(join_audio_artist, sortVar=TRUE, plot=F))
print(faltantes$combinations)
Patron Comun Canciones del Chart
#funcion nomaliza z score
scale_vble <- function(x){
(x - mean(x, na.rm = T))/sd(x, na.rm = T)
}
# Histograma con variables escaladas
join_audio_artist_complete <- na.omit(join_audio_artist)
join_audio_artist_complete_scale <- scale(join_audio_artist_complete %>% select(features_num) )
nrow(join_audio_artist_complete)
df_audio_features_complete <- na.omit(df_audio_features)
df_audio_features_complete_scale <- scale(df_audio_features_complete %>% select(features_num) )
nrow(df_audio_features_complete)
plot(density(join_audio_artist_complete_scale[,"danceability"]), main = "Histograma de danceabilty")
plot(density(df_audio_features_complete_scale[,"danceability"]), main = "Histograma de danceabilty")
lines(density(df_audio_features_complete_scale[,"danceability "]))
nrow(join_audio_artist_complete %>%
select(artist_name, track_name,features_num) %>%
distinct())
join_audio_artist_complete %>%
select(features_num) %>%
mutate_all(scale_vble) %>%
mutate(is_chart = "chart") %>%
rbind(df_audio_features_complete %>%
select(features_num) %>%
mutate_all(scale_vble) %>%
mutate(is_chart= "all")) %>%
gather(key = variable, value = valor, 1:10) %>%
# filter(!(variable %in% c("instrumentalness", "speechiness" )) ) %>%
filter(variable== "danceability" ) %>%
ggplot( aes(valor, fill = is_chart))+
geom_density(alpha = 0.2)#+
# facet_wrap(~variable, ncol=2)
for(i in features_num){
join_audio_artist_complete %>%
select(features_num) %>%
mutate_all(scale_vble) %>%
mutate(is_chart = "chart") %>%
rbind(df_audio_features_complete %>%
select(features_num) %>%
mutate_all(scale_vble) %>%
mutate(is_chart= "all")) %>%
gather(key = variable, value = valor, 1:10) %>%
# filter(!(variable %in% c("instrumentalness", "speechiness" )) ) %>%
filter(variable == i) %>%
ggplot( aes(valor, fill = is_chart))+
geom_density(alpha = 0.2)#+
# facet_wrap(~variable, ncol=2)
}
Atributos de audio a analizar
| acousticness |
Medida de confianza entre ceroo y 1 sobre si un tema es acústico (1 representa alta positibilidad de que sea acústico) |
Flotante |
| danceability |
Describe que tan adecuado es el tema para ser bailado, basado en una combinación de elementos musicales, como el tiempo, la estabilidad rítmica, la fuerza de los beats y la estabilidad general (valores entre 0 y 1, donde 0 implica poco bailable) |
Flotante |
| disc_number |
El número de disco (en general es 1, salvo que el album consista en más de un disco) |
Entero |
| duration_ms |
Duración del track en milisegundos |
Entero |
| energy |
Medida entre 0 y 1 que representa la percepción de intensidad y actividad en los temas. Usualmente, los temas energéticos suenan rápidos, fuertes y ruidoso (e.g. death metal tiene alta energía, mientras que los preludios de Bach puntuan bajo en la escala). Las características que contribuyen a este atributo son el rango dinámico (diferencia de energía (dB) entre el nivel de sonido más bajo y el más alto), el volumen o sonoridad percibida (métrica de intensidad), el timbre, la tasa aparición y la entropía. |
Float |
| explicit |
Detecta si un tema contiene lenguaje explícito (donde false es igual a “no se detecta presencia”) |
Booleano |
| instrumentalness |
Predice si un tema no contiene voces o cantos. Sonidos como “ooh” y “aah” son tratados como instrumentos en este contexto. El rap o palabras habladas en un tema son claramente voces. Los valores cercanos a 1 indican mayor probabilidad de que un tema no contenga voces en su contenido. Valores sobre 0.5 pueden interpretarse como temas más instrumentales, pero la confianza es mayor a medida que el valor se acerca a 1. |
Float |
| key |
El tono en el que está la canción. Se utiliza la notación standar Pitch Class para mapear los tonos en enteros. Por ejemplo: 0 = C, 1 = C♯/D♭, 2 = D, etc. Los nombres que estos enteros representan están en la variable key_name |
Categórica |
| mode |
Mdo en el cual está la canción, es decir, el tipo de escala de donde se deriva su contenido melódico. Los tonos mayores se represetan con 1 y los menores con 0. La variable mode_name describe el contenido de los valores (mayor o menor) y la variable key_mode sintetiza la información de key y mode |
Categórica (dummy) |
| liveness |
Detecta la presencia de audiencia en la grabación. Niveles más altos de la variable representan una probabilidad mayor de que el tema haya sido grabado en vivo. Un valor por sobre 0.8 provee una fuerte confianza de que el tema haya sido en vivo. |
Flotante |
| loudness |
Volumen general de una canción en decibles (dB). Los valores de la variable están promediados a lo largo de todo el tema y son útiles para comparar sus volumenes relativos. El volumen es una cualidad del sonido que esta principalmente correlacionada con la fuerza física (amplitud). Los valores oscilan en un rango entre -60 y 0 dB |
Flotante |
| speechines |
Detecta la presencia de palabras habladas en un tema. Mientras los temas posean una mayor porción de partes exclusivamente habladas (e.g. charlas, audio book, poemas) los valores estarán cerca de 1. Los valores sobre 0.66 describen temas que son probablemente hechos enteramente de palabras habladas; mientras uqe valores entre 0.33 y 0.66 describen temas que pueden contener tanto musica como habla, quizas en diferentes secciones o superpuestos (como en el rap); y valores menores a 0.33 son probablemente temas con sólo música u audios sin palabras habladas. |
Flotante |
| tempo |
El tiempo general estimado de un tema medido en beats por minuto (BPB). El tiempo es la velocidad o ritmo de una canción y se deriva directamente de la duración promedio de los beats |
Flotante |
| time_signature |
Estimación general del compás de una canción. El compás es una métrica convencional que especifica cuántos golpes/beats hay por unidad de tiempo dentro de una canción. |
Entero |
| valence |
Medida entre 0 y 1 que describe la “positividad musical” transmitida por una canción. Temas con altos valores suenan más positivos (e.g. felices, alegres, eufóricos), mientras temas con bajos valores suenan más negativos (e.g. tristes, depresivos, enojados) |
Flotante |
LS0tDQp0aXRsZTogImZlYXR1cmVzX2NhdGVnb3JpY29zIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KHJlYWR4bCkNCmxpYnJhcnkocmVzaGFwZSkNCmxpYnJhcnkocmVzaGFwZTIpDQpsaWJyYXJ5KG1vbmdvbGl0ZSkNCmBgYA0KDQoNCg0KYGBge3J9DQpseXJpY3MgPSBtb25nbyhjb2xsZWN0aW9uID0gImx5cmljcyIsIGRiID0gInNwb3RpZnlfZG0iICkNCmRmX2x5cmljcyA8LSBseXJpY3MkZmluZCgne30nKQ0KDQp3cml0ZS5jc3YoZGZfbHlyaWNzLCAiZGF0YS9kZl9seXJpY3MuY3N2IikNCg0KZGZfbHlyaWNzIDwtIHJlYWQuY3N2KCJkYXRhL2RmX2x5cmljcy5jc3YiKQ0KDQpgYGANCg0KDQoNCmBgYHtyfQ0KI2RpciBNYXRlbw0KZGZfYXJ0aXN0IDwtIHJlYWQuY3N2KCJkYXRhL2RmX2FydGlzdF9zaW5fZHVwbGljYWRvcy5jc3YiKQ0KDQpkZl9jaGFydHMgPC0gcmVhZC5jc3YoImRhdGEvZGZfY2hhcnRzX3Npbl9kdXBsaWNhZG9zLmNzdiIpDQoNCmRmX2F1ZGlvX2ZlYXR1cmVzIDwtIHJlYWQuY3N2KCJkYXRhL2F1ZGlvX2ZlYXR1cmVzX3BsYW5vX3Npbl9kdXBsaWNhZG9zLmNzdiIpDQoNCm5yb3coZGZfY2hhcnRzKQ0KbnJvdyhkZl9hdWRpb19mZWF0dXJlcykNCmBgYA0KDQoNCmBgYHtyfQ0KZmVhdHVyZXNfY2F0ZWdvcmljYXMgPC1jKCAnZXhwbGljaXQnLCAna2V5X25hbWUnLCAnbW9kZV9uYW1lJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgImtleV9tb2RlIiwgImFsYnVtX3R5cGUiKSMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAjImFydGlzdF9jb25jYXQiLCAibWFya2V0c19jb25jYXQiKQ0KDQpmZWF0dXJlc19jb250aW51YXMgPC0gYygnYWNvdXN0aWNuZXNzJywgJ2RhbmNlYWJpbGl0eScsICdkdXJhdGlvbl9tcycsICdlbmVyZ3knLCANCiAgICAgICAgICAgICAgJ2luc3RydW1lbnRhbG5lc3MnLCAnbGl2ZW5lc3MnLCAnbG91ZG5lc3MnLCAnc3BlZWNoaW5lc3MnLCAgDQogICAgICAgICAgICAgICd0ZW1wbycsICd2YWxlbmNlJykNCiMgZmVhdHVyZXNfY2F0ZWdvcmljb3MgPC1jKCBleHBsaWNpdCwgZGlzY19udW1iZXIsa2V5X25hbWUsIG1vZGVfbmFtZSwga2V5X21vZGUsIGFsYnVtX3R5cGUpDQojIHRpbWVfc2lnbmF0dXJlDQoNCnN1bW1hcnkoZGZfYXVkaW9fZmVhdHVyZXNbLGZlYXR1cmVzX2NhdGVnb3JpY2FzXSkNCg0KdGFibGUoZGZfYXVkaW9fZmVhdHVyZXMkYWxidW1fdHlwZSkNCmBgYA0KDQpgYGB7cn0NCiNvYnNlcnZvIHF1ZSBhcnRpc3RhcyB5IHRpcG8gZGUgYWxidW5lcyBzb24gbG9zIHF1ZSB0aWVuZW4gbXVjaG9zIGRpc2NfbnVtYmVyDQp1bmlxdWUoZGZfYXVkaW9fZmVhdHVyZXNbZGZfYXVkaW9fZmVhdHVyZXMkZGlzY19udW1iZXIgPiA4LF0kYXJ0aXN0X25hbWUpDQp1bmlxdWUoZGZfYXVkaW9fZmVhdHVyZXNbZGZfYXVkaW9fZmVhdHVyZXMkZGlzY19udW1iZXIgPiAxMCxdJGFsYnVtX3R5cGUpDQoNCnNvcnQodGFibGUoZGZfYXVkaW9fZmVhdHVyZXNbLCJrZXlfbmFtZSJdKSwgZGVjcmVhc2luZyA9IFQpDQpgYGANCg0KDQpgYGB7cn0NCg0KZm9yKGkgaW4gZmVhdHVyZXNfY2F0ZWdvcmljb3Mpew0KICBwcmludChpKQ0KICBiYXJwbG90KHNvcnQodGFibGUoZGZfYXVkaW9fZmVhdHVyZXNbLGldKSxkZWNyZWFzaW5nID0gVCksIG1haW4gPSBpLCBsYXM9MikNCiAgIyBwaWUodGFibGUoZGZfZmVhdHVyZXNfY2F0ZWdvcmljb3NbLGldKSkNCn0NCg0KDQpgYGANCg0KDQojIyBDb3JyZWxhY2lvbiBlbnRyZSB2YXJpYWJsZXMgY2F0ZWfDs3JpY2FzDQoNCmBgYHtyfQ0KdGFibGFfa2V5X2FsYnVtIDwtIHRhYmxlKGRmX2F1ZGlvX2ZlYXR1cmVzJGtleV9uYW1lLCBkZl9hdWRpb19mZWF0dXJlcyRhbGJ1bV90eXBlKQ0KY2F0KCJUYWJsYSBkZSBjb250aWdlbmNpYSBlbnRyZSBrZXkgeSBhbGJ1bSB0eXBlXG4iKQ0KdGFibGFfa2V5X2FsYnVtDQpjaGlzcS50ZXN0KHRhYmxhX2tleV9tb2RlKQ0KDQpgYGANClNlIG9ic2VydmFuIHZhbG9yZXMgYWx0b3MgZGVsIHRlc3QgY2hpIGN1YWRyYWRvLCBwb3IgbG8gcXVlIHNlIHB1ZWRlIHJlY2hhemFyIGxhIEgwICh2YXJpYWJsZXMgY2F0ZWdvcmljYXMgaW5kZXBlbmRpZW50ZXMpIHkgYWZpcm1hciBsYSBkZXBlbmRlbmNpYSBkZSBsYXMgdmFyaWFibGVzDQoNCmBgYHtyfQ0KdGFibGFfa2V5X21vZGUgPC0gdGFibGUoZGZfYXVkaW9fZmVhdHVyZXMkZXhwbGljaXQsIGRmX2F1ZGlvX2ZlYXR1cmVzJGFsYnVtX3R5cGUpDQpjYXQoIlRhYmxhIGRlIGNvbnRpZ2VuY2lhIGVudHJlIGtleSB5IGFsYnVtIHR5cGVcbiIpDQp0YWJsYV9rZXlfbW9kZQ0KY2hpc3EudGVzdCh0YWJsYV9rZXlfbW9kZSkNCg0KYGBgDQoNCmBgYHtyfQ0KY29udGFyX21hcmtldCA8LSBmdW5jdGlvbih4KXsNCnEgPC0gbGVuZ3RoKHVubGlzdChzdHJzcGxpdCh4LCBzcGxpdCA9ICIsIikpKQ0KcmV0dXJuIChxKQ0KICB9DQpkZl9hdWRpb19mZWF0dXJlcyRjYW50X21hcmtldHMgPC0gc2FwcGx5KGRmX2F1ZGlvX2ZlYXR1cmVzWywibWFya2V0c19jb25jYXQiXSwgY29udGFyX21hcmtldCkNCg0Kc3VtbWFyeShkZl9hdWRpb19mZWF0dXJlcyRjYW50X21hcmtldHMpICNoYXkgY2FuY2lvbmVzIGVuIGNlcm8gcGHDrXNlcy4gRXN0w6FuIGRhZGFzIGRlIGJhamENCg0KDQpgYGANCg0KYGBge3J9DQp4IDwtIGRmX2F1ZGlvX2ZlYXR1cmVzICU+JSANCiAgZ3JvdXBfYnkodHJhY2tfbmFtZSwgZXh0ZXJuYWxfdXJsc19zcG90aWZ5KQ0KDQp4JGNhbnRfbWFya2V0cyA8LSBzYXBwbHkoeFssIm1hcmtldHNfY29uY2F0Il0sIGNvbnRhcl9tYXJrZXQpDQoNCnN1bW1hcnkoeCRjYW50X21hcmtldHMpICNoYXkgY2FuY2lvbmVzIGVuIGNlcm8gcGHDrXNlcy4gRXN0w6FuIGRhZGFzIGRlIGJhamENCg0KDQoNCmBgYA0KDQoNCiMjIEpvaW4gQ2hhcnRzIHkgQXVkaW8gRmVhdHVyZXMNCg0KIyMjIE51ZXZhIGtleSBkZSBhcnRpc3QgcGFyYSBlbCBKT0lODQpgYGB7cn0NCnggPC0gZGZfYXVkaW9fZmVhdHVyZXMgJT4lIA0KICBncm91cF9ieSh0cmFja19uYW1lLCBleHRlcm5hbF91cmxzX3Nwb3RpZnkpICU+JSANCiAgbXV0YXRlKGFydGlzdF9uZXcgPSBwYXN0ZShhcnRpc3RfbmFtZSwgY29sbGFwc2UgPSAiLHwsIikpICU+JQ0KICB1bmdyb3VwKCkgJT4lIA0KICBtdXRhdGUoYXJ0aXN0X2tleSA9IHN1YigiLHwsLioiLCAiIiwgYXJ0aXN0X25ldykpICU+JSANCiAgc2VsZWN0KGFydGlzdF9uYW1lLCBhcnRpc3RfbmV3LCBhcnRpc3Rfa2V5LCBldmVyeXRoaW5nKC4pKSAlPiUgDQogIGRpc3RpbmN0KGFydGlzdF9rZXksIGV4dGVybmFsX3VybHNfc3BvdGlmeSwgLmtlZXBfYWxsID0gVCkNCg0KbGVuZ3RoKHhbMSx4JG1hcmtldHNfY29uY2F0XSkNCmBgYA0KDQoNCmBgYHtyfQ0Kam9pbl9hdWRpb19jaGFydHMgPC0geCAlPiUgDQogIHNlbGVjdCgiYXJ0aXN0X25hbWUiLCJhcnRpc3RfbmV3IiwiYXJ0aXN0X2tleSIsDQogICAgICAgICAidHJhY2tfbmFtZSIsICJleHRlcm5hbF91cmxzX3Nwb3RpZnkiLA0KICAgICAgICAgZmVhdHVyZXNfY29udGludWFzLCBmZWF0dXJlc19jYXRlZ29yaWNhcykgJT4lIA0KICByaWdodF9qb2luKCBkZl9jaGFydHMgJT4lDQogICAgICAgICAgICAgICBzZWxlY3QoICJUcmFja19OYW1lIiwgIkFydGlzdCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAiVVJMIiwiUG9zaXRpb24iLCAiU3RyZWFtcyIsICJ3ZWVrX3N0YXJ0IiwgIndlZWtfZW5kIiksDQogICAgICAgICAgICAgICBieSA9IGMoDQogICAgICAgICAgICAgICAgICMgInRyYWNrX25hbWUiID0gIlRyYWNrX05hbWUiLCANCiAgICAgICAgICAgICAgICAgICAgICAiYXJ0aXN0X2tleSIgPSJBcnRpc3QiLCANCiAgICAgICAgICAgICAgICAgICAgICAiZXh0ZXJuYWxfdXJsc19zcG90aWZ5IiA9ICJVUkwiKSkNCmBgYA0KDQoNCg0KYGBge3J9DQojIyMjIyMjIyMjIyMjIyMjIyMjDQp5IDwtIGpvaW5fYXVkaW9fY2hhcnRzICU+JSANCiAgICBmaWx0ZXIoZ3JlcGwoImQzMk02IiwgZXh0ZXJuYWxfdXJsc19zcG90aWZ5KSkjICU+JSANCiAgIyBkaXN0aW5jdChQb3NpdGlvbiwgd2Vla19zdGFydCkNCg0KYGBgDQoNCg0KYGBge3J9DQpnbGltcHNlKGpvaW5fYXVkaW9fY2hhcnRzKQ0KDQpucm93KGRmX2F1ZGlvX2ZlYXR1cmVzKQ0KbnJvdyh4KQ0KDQpucm93KGRmX2NoYXJ0cykNCm5yb3coam9pbl9hdWRpb19jaGFydHMpDQoNCnN1bSghY29tcGxldGUuY2FzZXMoZGZfYXVkaW9fZmVhdHVyZXMpKQ0Kc3VtKCFjb21wbGV0ZS5jYXNlcyhqb2luX2F1ZGlvX2NoYXJ0cykpDQpzdW0oY29tcGxldGUuY2FzZXMoam9pbl9hdWRpb19jaGFydHMpKQ0KDQpsZW5ndGgodW5pcXVlKGpvaW5fYXVkaW9fY2hhcnRzJGFydGlzdF9uYW1lKSkNCg0KICAjIGZpbHRlcihncmVwbCgiZDMyTTYiLCBleHRlcm5hbF91cmxzX3Nwb3RpZnkpKSAlPiUgDQoNCmBgYA0KDQoNCg0KYGBge3J9DQp4DQoNCnggJT4lIHNlbGVjdChhcnRpc3Rfa2V5LCBhcnRpc3RfbmV3LGV2ZXJ5dGhpbmcoLikpICU+JSANCiAgZmlsdGVyKGdyZXBsKCJ8IiwgYXJ0aXN0X25ldykpDQpgYGANCg0KDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQpgYGB7cn0NCmpvaW5fYXVkaW9fYXJ0aXN0IDwtIGRmX2F1ZGlvX2ZlYXR1cmVzICU+JSANCiAgc2VsZWN0KCJhcnRpc3RfbmFtZSIsICJ0cmFja19uYW1lIiwgZmVhdHVyZXNfbnVtLCBmZWF0dXJlc19jYXRlZ29yaWNvcykgJT4lIA0KICByaWdodF9qb2luKCBkZl9jaGFydHMgJT4lDQogICAgICAgICAgICAgICBzZWxlY3QoICJUcmFja19OYW1lIiwgIkFydGlzdCIgKSwgDQogICAgICAgICAgICAgICAgICAgICAgIyAiUG9zaXRpb24iLCAiU3RyZWFtcyIsICJ3ZWVrX3N0YXJ0IiwgIndlZWtfZW5kIiksDQogICAgICAgICAgICAgIGJ5ID0gYygidHJhY2tfbmFtZSIgPSAiVHJhY2tfTmFtZSIsICJhcnRpc3RfbmFtZSIgPSJBcnRpc3QiICApKSANCg0KYGBgDQoNCmBgYHtyfQ0Kam9pbl9hdWRpb19hcnRpc3QgPC0gZGZfY2hhcnRzICU+JQ0KICBzZWxlY3QoICJUcmFja19OYW1lIiwgIkFydGlzdCIsICJVUkwiLCAiUG9zaXRpb24iLCAiU3RyZWFtcyIsICJ3ZWVrX3N0YXJ0IiwgIndlZWtfZW5kIikgJT4lICANCiAgIyBkaXN0aW5jdCgpICU+JQ0KICBsZWZ0X2pvaW4oIGRmX2F1ZGlvX2ZlYXR1cmVzICU+JQ0KICAgICAgICAgICAgICAgIHNlbGVjdCgiYXJ0aXN0X25hbWUiLCAidHJhY2tfbmFtZSIsICJleHRlcm5hbF91cmxzX3Nwb3RpZnkiLCBmZWF0dXJlc19udW0sIGZlYXR1cmVzX2NhdGVnb3JpY29zKSwgDQogICAgICAgICAgICAgIGJ5ID0gYyggIlVSTCI9ICJleHRlcm5hbF91cmxzX3Nwb3RpZnkiICApKSANCmpvaW5fYXVkaW9fYXJ0aXN0DQoNCiMgZ2xpbXBzZShkZl9hdWRpb19mZWF0dXJlcykNCiMgZ2xpbXBzZShkZl9jaGFydHMpDQpgYGANCg0KIyMgQW5hbGlzaXMgZGUgTkEncyBkZSBBdWRpbyBGZWF0dXJlDQpgYGB7cn0NCnN1bShpcy5uYShqb2luX2F1ZGlvX2FydGlzdCkpDQpzdW0oIWNvbXBsZXRlLmNhc2VzKGpvaW5fYXVkaW9fYXJ0aXN0KSkNCg0Kc3VtKGlzLm5hKGRmX2F1ZGlvX2ZlYXR1cmVzKSkNCnN1bShpcy5uYShkZl9jaGFydHMpKQ0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShtaWNlKQ0KbWQucGF0dGVybihqb2luX2F1ZGlvX2FydGlzdCwgcm90YXRlLm5hbWVzID0gVCkNCmBgYA0KDQoNCmBgYHtyfQ0KbGlicmFyeShWSU0pDQojIFByb3BvcmNpw7NuIGRlIGNhZGEgY29tYmluYWNpw7NuDQpmYWx0YW50ZXMgPSBzdW1tYXJ5KGFnZ3Ioam9pbl9hdWRpb19hcnRpc3QsIHNvcnRWYXI9VFJVRSwgcGxvdD1GKSkNCnByaW50KGZhbHRhbnRlcyRjb21iaW5hdGlvbnMpDQpgYGANCg0KDQojIyBQYXRyb24gQ29tdW4gQ2FuY2lvbmVzIGRlbCBDaGFydA0KDQpgYGB7cn0NCiNmdW5jaW9uIG5vbWFsaXphIHogc2NvcmUNCnNjYWxlX3ZibGUgPC0gZnVuY3Rpb24oeCl7DQogICh4IC0gbWVhbih4LCBuYS5ybSA9IFQpKS9zZCh4LCBuYS5ybSA9IFQpDQp9DQoNCiMgSGlzdG9ncmFtYSBjb24gdmFyaWFibGVzIGVzY2FsYWRhcyANCmpvaW5fYXVkaW9fYXJ0aXN0X2NvbXBsZXRlIDwtIG5hLm9taXQoam9pbl9hdWRpb19hcnRpc3QpDQpqb2luX2F1ZGlvX2FydGlzdF9jb21wbGV0ZV9zY2FsZSA8LSBzY2FsZShqb2luX2F1ZGlvX2FydGlzdF9jb21wbGV0ZSAlPiUgc2VsZWN0KGZlYXR1cmVzX251bSkgKQ0KbnJvdyhqb2luX2F1ZGlvX2FydGlzdF9jb21wbGV0ZSkNCg0KZGZfYXVkaW9fZmVhdHVyZXNfY29tcGxldGUgPC0gbmEub21pdChkZl9hdWRpb19mZWF0dXJlcykNCmRmX2F1ZGlvX2ZlYXR1cmVzX2NvbXBsZXRlX3NjYWxlIDwtIHNjYWxlKGRmX2F1ZGlvX2ZlYXR1cmVzX2NvbXBsZXRlICU+JSAgc2VsZWN0KGZlYXR1cmVzX251bSkgKQ0KbnJvdyhkZl9hdWRpb19mZWF0dXJlc19jb21wbGV0ZSkNCiAgDQoNCg0KcGxvdChkZW5zaXR5KGpvaW5fYXVkaW9fYXJ0aXN0X2NvbXBsZXRlX3NjYWxlWywiZGFuY2VhYmlsaXR5Il0pLCBtYWluID0gIkhpc3RvZ3JhbWEgZGUgZGFuY2VhYmlsdHkiKQ0KcGxvdChkZW5zaXR5KGRmX2F1ZGlvX2ZlYXR1cmVzX2NvbXBsZXRlX3NjYWxlWywiZGFuY2VhYmlsaXR5Il0pLCBtYWluID0gIkhpc3RvZ3JhbWEgZGUgZGFuY2VhYmlsdHkiKQ0KbGluZXMoZGVuc2l0eShkZl9hdWRpb19mZWF0dXJlc19jb21wbGV0ZV9zY2FsZVssImRhbmNlYWJpbGl0eSAiXSkpDQpgYGANCg0KYGBge3J9DQpucm93KGpvaW5fYXVkaW9fYXJ0aXN0X2NvbXBsZXRlICU+JSANCiAgc2VsZWN0KGFydGlzdF9uYW1lLCB0cmFja19uYW1lLGZlYXR1cmVzX251bSkgJT4lIA0KICBkaXN0aW5jdCgpKQ0KDQpqb2luX2F1ZGlvX2FydGlzdF9jb21wbGV0ZSAlPiUNCiAgc2VsZWN0KGZlYXR1cmVzX251bSkgJT4lIA0KICBtdXRhdGVfYWxsKHNjYWxlX3ZibGUpICU+JSANCiAgbXV0YXRlKGlzX2NoYXJ0ID0gImNoYXJ0IikgJT4lDQogIHJiaW5kKGRmX2F1ZGlvX2ZlYXR1cmVzX2NvbXBsZXRlICU+JSANCiAgICAgICAgICBzZWxlY3QoZmVhdHVyZXNfbnVtKSAlPiUNCiAgICAgICAgICBtdXRhdGVfYWxsKHNjYWxlX3ZibGUpICU+JQ0KICAgICAgICAgIG11dGF0ZShpc19jaGFydD0gImFsbCIpKSAlPiUNCiAgZ2F0aGVyKGtleSA9IHZhcmlhYmxlLCB2YWx1ZSA9IHZhbG9yLCAxOjEwKSAlPiUgDQogICMgZmlsdGVyKCEodmFyaWFibGUgJWluJSBjKCJpbnN0cnVtZW50YWxuZXNzIiwgInNwZWVjaGluZXNzIiApKSApICU+JQ0KICBmaWx0ZXIodmFyaWFibGU9PSAiZGFuY2VhYmlsaXR5IiApICU+JQ0KICBnZ3Bsb3QoIGFlcyh2YWxvciwgZmlsbCA9IGlzX2NoYXJ0KSkrIA0KICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjIpIysNCiAgIyBmYWNldF93cmFwKH52YXJpYWJsZSwgbmNvbD0yKQ0KYGBgDQoNCg0KYGBge3J9DQpmb3IoaSBpbiBmZWF0dXJlc19udW0pew0Kam9pbl9hdWRpb19hcnRpc3RfY29tcGxldGUgJT4lDQogIHNlbGVjdChmZWF0dXJlc19udW0pICU+JSANCiAgbXV0YXRlX2FsbChzY2FsZV92YmxlKSAlPiUgDQogIG11dGF0ZShpc19jaGFydCA9ICJjaGFydCIpICU+JQ0KICByYmluZChkZl9hdWRpb19mZWF0dXJlc19jb21wbGV0ZSAlPiUgDQogICAgICAgICAgc2VsZWN0KGZlYXR1cmVzX251bSkgJT4lDQogICAgICAgICAgbXV0YXRlX2FsbChzY2FsZV92YmxlKSAlPiUNCiAgICAgICAgICBtdXRhdGUoaXNfY2hhcnQ9ICJhbGwiKSkgJT4lDQogIGdhdGhlcihrZXkgPSB2YXJpYWJsZSwgdmFsdWUgPSB2YWxvciwgMToxMCkgJT4lIA0KICAjIGZpbHRlcighKHZhcmlhYmxlICVpbiUgYygiaW5zdHJ1bWVudGFsbmVzcyIsICJzcGVlY2hpbmVzcyIgKSkgKSAlPiUNCiAgZmlsdGVyKHZhcmlhYmxlICA9PSBpKSAlPiUNCiAgZ2dwbG90KCBhZXModmFsb3IsIGZpbGwgPSBpc19jaGFydCkpKyANCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC4yKSMrDQogICMgZmFjZXRfd3JhcCh+dmFyaWFibGUsIG5jb2w9MikNCn0gIA0KYGBgDQoNCg0KIyMgQXRyaWJ1dG9zIGRlIGF1ZGlvIGEgYW5hbGl6YXINCg0KRmVhdHVyZSB8IERlc2NyaXBjacOzbiB8IFRpcG8NCi0tLS0gfCAtLS0tIHwgLS0tLQ0KYWNvdXN0aWNuZXNzIHxNZWRpZGEgZGUgY29uZmlhbnphIGVudHJlIGNlcm9vIHkgMSBzb2JyZSBzaSB1biB0ZW1hIGVzIGFjw7pzdGljbyAoMSByZXByZXNlbnRhIGFsdGEgcG9zaXRpYmlsaWRhZCBkZSBxdWUgc2VhIGFjw7pzdGljbyl8CUZsb3RhbnRlDQpkYW5jZWFiaWxpdHkgfERlc2NyaWJlIHF1ZSB0YW4gYWRlY3VhZG8gZXMgZWwgdGVtYSBwYXJhIHNlciBiYWlsYWRvLCBiYXNhZG8gZW4gdW5hIGNvbWJpbmFjacOzbiBkZSBlbGVtZW50b3MgbXVzaWNhbGVzLCBjb21vIGVsIHRpZW1wbywgbGEgZXN0YWJpbGlkYWQgcsOtdG1pY2EsIGxhIGZ1ZXJ6YSBkZSBsb3MgYmVhdHMgeSBsYSBlc3RhYmlsaWRhZCBnZW5lcmFsICh2YWxvcmVzIGVudHJlIDAgeSAxLCBkb25kZSAwIGltcGxpY2EgcG9jbyBiYWlsYWJsZSkgIHwgRmxvdGFudGUNCmRpc2NfbnVtYmVyIHwgRWwgbsO6bWVybyBkZSBkaXNjbyAoZW4gZ2VuZXJhbCBlcyAxLCBzYWx2byBxdWUgZWwgYWxidW0gY29uc2lzdGEgZW4gbcOhcyBkZSB1biBkaXNjbykgIHwgRW50ZXJvDQpkdXJhdGlvbl9tcyB8IER1cmFjacOzbiBkZWwgdHJhY2sgZW4gbWlsaXNlZ3VuZG9zIHwgRW50ZXJvDQplbmVyZ3kgfCBNZWRpZGEgZW50cmUgMCB5IDEgcXVlIHJlcHJlc2VudGEgbGEgcGVyY2VwY2nDs24gZGUgaW50ZW5zaWRhZCB5IGFjdGl2aWRhZCBlbiBsb3MgdGVtYXMuIFVzdWFsbWVudGUsIGxvcyB0ZW1hcyBlbmVyZ8OpdGljb3Mgc3VlbmFuIHLDoXBpZG9zLCBmdWVydGVzIHkgcnVpZG9zbyAoZS5nLiBkZWF0aCBtZXRhbCB0aWVuZSBhbHRhIGVuZXJnw61hLCBtaWVudHJhcyBxdWUgbG9zIHByZWx1ZGlvcyBkZSBCYWNoIHB1bnR1YW4gYmFqbyBlbiBsYSBlc2NhbGEpLiBMYXMgY2FyYWN0ZXLDrXN0aWNhcyBxdWUgY29udHJpYnV5ZW4gYSBlc3RlIGF0cmlidXRvIHNvbiBlbCByYW5nbyBkaW7DoW1pY28gKGRpZmVyZW5jaWEgZGUgZW5lcmfDrWEgKGRCKSBlbnRyZSBlbCBuaXZlbCBkZSBzb25pZG8gbcOhcyBiYWpvIHkgZWwgbcOhcyBhbHRvKSwgZWwgdm9sdW1lbiBvIHNvbm9yaWRhZCBwZXJjaWJpZGEgKG3DqXRyaWNhIGRlIGludGVuc2lkYWQpLCBlbCB0aW1icmUsIGxhIHRhc2EgYXBhcmljacOzbiB5IGxhIGVudHJvcMOtYS58IEZsb2F0DQpleHBsaWNpdCB8IERldGVjdGEgc2kgdW4gdGVtYSBjb250aWVuZSBsZW5ndWFqZSBleHBsw61jaXRvIChkb25kZSBmYWxzZSBlcyBpZ3VhbCBhICJubyBzZSBkZXRlY3RhIHByZXNlbmNpYSIpIHwgQm9vbGVhbm8NCmluc3RydW1lbnRhbG5lc3MgfCBQcmVkaWNlIHNpIHVuIHRlbWEgbm8gY29udGllbmUgdm9jZXMgbyBjYW50b3MuIFNvbmlkb3MgY29tbyDigJxvb2jigJ0geSDigJxhYWjigJ0gc29uIHRyYXRhZG9zIGNvbW8gaW5zdHJ1bWVudG9zIGVuIGVzdGUgY29udGV4dG8uIEVsIHJhcCBvIHBhbGFicmFzIGhhYmxhZGFzIGVuIHVuIHRlbWEgc29uIGNsYXJhbWVudGUgdm9jZXMuIExvcyB2YWxvcmVzIGNlcmNhbm9zIGEgMSBpbmRpY2FuIG1heW9yIHByb2JhYmlsaWRhZCBkZSBxdWUgdW4gdGVtYSBubyBjb250ZW5nYSB2b2NlcyBlbiBzdSBjb250ZW5pZG8uIFZhbG9yZXMgc29icmUgMC41IHB1ZWRlbiBpbnRlcnByZXRhcnNlIGNvbW8gdGVtYXMgbcOhcyBpbnN0cnVtZW50YWxlcywgcGVybyBsYSBjb25maWFuemEgZXMgbWF5b3IgYSBtZWRpZGEgcXVlIGVsIHZhbG9yIHNlIGFjZXJjYSBhIDEuIHwgRmxvYXQNCmtleSB8IEVsIHRvbm8gZW4gZWwgcXVlIGVzdMOhIGxhIGNhbmNpw7NuLiBTZSB1dGlsaXphIGxhIG5vdGFjacOzbiBzdGFuZGFyIFBpdGNoIENsYXNzIHBhcmEgbWFwZWFyIGxvcyB0b25vcyBlbiBlbnRlcm9zLiBQb3IgZWplbXBsbzogMCA9IEMsIDEgPSBD4pmvL0Tima0sIDIgPSBELCBldGMuIExvcyBub21icmVzIHF1ZSBlc3RvcyBlbnRlcm9zIHJlcHJlc2VudGFuIGVzdMOhbiBlbiBsYSB2YXJpYWJsZSBrZXlfbmFtZSB8IENhdGVnw7NyaWNhDQptb2RlIHwgTWRvIGVuIGVsIGN1YWwgZXN0w6EgbGEgY2FuY2nDs24sIGVzIGRlY2lyLCBlbCB0aXBvIGRlIGVzY2FsYSBkZSBkb25kZSBzZSBkZXJpdmEgc3UgY29udGVuaWRvIG1lbMOzZGljby4gTG9zIHRvbm9zIG1heW9yZXMgc2UgcmVwcmVzZXRhbiBjb24gMSB5IGxvcyBtZW5vcmVzIGNvbiAwLiBMYSB2YXJpYWJsZSBtb2RlX25hbWUgZGVzY3JpYmUgZWwgY29udGVuaWRvIGRlIGxvcyB2YWxvcmVzIChtYXlvciBvIG1lbm9yKSB5IGxhIHZhcmlhYmxlIGtleV9tb2RlIHNpbnRldGl6YSBsYSBpbmZvcm1hY2nDs24gZGUga2V5IHkgbW9kZSB8IENhdGVnw7NyaWNhIChkdW1teSkNCmxpdmVuZXNzIHwgRGV0ZWN0YSBsYSBwcmVzZW5jaWEgZGUgYXVkaWVuY2lhIGVuIGxhIGdyYWJhY2nDs24uIE5pdmVsZXMgbcOhcyBhbHRvcyBkZSBsYSB2YXJpYWJsZSByZXByZXNlbnRhbiB1bmEgcHJvYmFiaWxpZGFkIG1heW9yIGRlIHF1ZSBlbCB0ZW1hIGhheWEgc2lkbyBncmFiYWRvIGVuIHZpdm8uIFVuIHZhbG9yIHBvciBzb2JyZSAwLjggcHJvdmVlIHVuYSBmdWVydGUgY29uZmlhbnphIGRlIHF1ZSBlbCB0ZW1hIGhheWEgc2lkbyBlbiB2aXZvLiB8IEZsb3RhbnRlDQpsb3VkbmVzcyB8IFZvbHVtZW4gZ2VuZXJhbCBkZSB1bmEgY2FuY2nDs24gZW4gZGVjaWJsZXMgKGRCKS4gTG9zIHZhbG9yZXMgZGUgbGEgdmFyaWFibGUgZXN0w6FuIHByb21lZGlhZG9zIGEgbG8gbGFyZ28gZGUgdG9kbyBlbCB0ZW1hIHkgc29uIMO6dGlsZXMgcGFyYSBjb21wYXJhciBzdXMgdm9sdW1lbmVzIHJlbGF0aXZvcy4gRWwgdm9sdW1lbiBlcyB1bmEgY3VhbGlkYWQgZGVsIHNvbmlkbyBxdWUgZXN0YSBwcmluY2lwYWxtZW50ZSBjb3JyZWxhY2lvbmFkYSBjb24gbGEgZnVlcnphIGbDrXNpY2EgKGFtcGxpdHVkKS4gTG9zIHZhbG9yZXMgb3NjaWxhbiBlbiB1biByYW5nbyBlbnRyZSAtNjAgeSAwIGRCIHwgRmxvdGFudGUNCnNwZWVjaGluZXMgfCBEZXRlY3RhIGxhIHByZXNlbmNpYSBkZSBwYWxhYnJhcyBoYWJsYWRhcyBlbiB1biB0ZW1hLiBNaWVudHJhcyBsb3MgdGVtYXMgcG9zZWFuIHVuYSBtYXlvciBwb3JjacOzbiBkZSBwYXJ0ZXMgZXhjbHVzaXZhbWVudGUgaGFibGFkYXMgKGUuZy4gY2hhcmxhcywgYXVkaW8gYm9vaywgcG9lbWFzKSBsb3MgdmFsb3JlcyBlc3RhcsOhbiBjZXJjYSBkZSAxLiBMb3MgdmFsb3JlcyBzb2JyZSAwLjY2IGRlc2NyaWJlbiB0ZW1hcyBxdWUgc29uIHByb2JhYmxlbWVudGUgaGVjaG9zIGVudGVyYW1lbnRlIGRlIHBhbGFicmFzIGhhYmxhZGFzOyBtaWVudHJhcyB1cWUgdmFsb3JlcyBlbnRyZSAwLjMzIHkgMC42NiBkZXNjcmliZW4gdGVtYXMgcXVlIHB1ZWRlbiBjb250ZW5lciB0YW50byBtdXNpY2EgY29tbyBoYWJsYSwgcXVpemFzIGVuIGRpZmVyZW50ZXMgc2VjY2lvbmVzIG8gc3VwZXJwdWVzdG9zIChjb21vIGVuIGVsIHJhcCk7IHkgdmFsb3JlcyBtZW5vcmVzIGEgMC4zMyBzb24gcHJvYmFibGVtZW50ZSB0ZW1hcyBjb24gc8OzbG8gbcO6c2ljYSB1IGF1ZGlvcyBzaW4gcGFsYWJyYXMgaGFibGFkYXMuIHwgRmxvdGFudGUNCnRlbXBvfCBFbCB0aWVtcG8gZ2VuZXJhbCBlc3RpbWFkbyBkZSB1biB0ZW1hIG1lZGlkbyBlbiBiZWF0cyBwb3IgbWludXRvIChCUEIpLiBFbCB0aWVtcG8gZXMgbGEgdmVsb2NpZGFkIG8gcml0bW8gZGUgdW5hIGNhbmNpw7NuIHkgc2UgZGVyaXZhIGRpcmVjdGFtZW50ZSBkZSBsYSBkdXJhY2nDs24gcHJvbWVkaW8gZGUgbG9zIGJlYXRzfCBGbG90YW50ZQ0KdGltZV9zaWduYXR1cmV8IEVzdGltYWNpw7NuIGdlbmVyYWwgZGVsIGNvbXDDoXMgZGUgdW5hIGNhbmNpw7NuLiBFbCBjb21ww6FzIGVzIHVuYSBtw6l0cmljYSBjb252ZW5jaW9uYWwgcXVlIGVzcGVjaWZpY2EgY3XDoW50b3MgZ29scGVzL2JlYXRzIGhheSBwb3IgdW5pZGFkIGRlIHRpZW1wbyBkZW50cm8gZGUgdW5hIGNhbmNpw7NuLiB8IEVudGVybw0KdmFsZW5jZSB8IE1lZGlkYSBlbnRyZSAwIHkgMSBxdWUgZGVzY3JpYmUgbGEgInBvc2l0aXZpZGFkIG11c2ljYWwiIHRyYW5zbWl0aWRhIHBvciB1bmEgY2FuY2nDs24uIFRlbWFzIGNvbiBhbHRvcyB2YWxvcmVzIHN1ZW5hbiBtw6FzIHBvc2l0aXZvcyAoZS5nLiBmZWxpY2VzLCBhbGVncmVzLCBldWbDs3JpY29zKSwgbWllbnRyYXMgdGVtYXMgY29uIGJham9zIHZhbG9yZXMgc3VlbmFuIG3DoXMgbmVnYXRpdm9zIChlLmcuIHRyaXN0ZXMsIGRlcHJlc2l2b3MsIGVub2phZG9zKSB8IEZsb3RhbnRlDQo=